package com.trade.common.scheduler;

import com.trade.common.utils.RegexpValidate;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;

/**
 * Class Description: 任务调度管理
 *
 * @Version v1.0 2017/6/22 0:19
 * @JDK version 1.8.0_51
 * @Author zfb
 */
@Log4j
@Component
public class TaskSchedulerManager {
    /**
     * logger日志
     */
    private static final Map<String, TaskRunnable> TASKS = new HashMap<>();
    private static final Map<String, ScheduledFuture<?>> SCHEDULED_FUTURE = new HashMap<>();

    private final static int POOL_SIZE = 128;

    //以当前线程执行任务。如果任务简单，可以直接使用这个类来执行。快捷方便。
    private ConcurrentTaskScheduler ct = new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(POOL_SIZE));

    /**
     * 启动一个计划任务
     *
     * @param task 当前进行的任务.
     */
    public void start(TaskRunnable task) throws Exception {
        try {
            if (StringUtils.isEmpty(task.getTaskId())) {
                throw new Exception("任务id不能为空.");
            }

            if (StringUtils.isEmpty(task.getTrigger())) {
                throw new Exception("任务的调度表达式不能为空.");
            }

            if (!RegexpValidate.checkCronExpression(task.getTrigger())) {
                throw new Exception("任务的调度表达式格式错误.");
            }

            ScheduledFuture<?> schedule = ct.schedule(task, new CronTrigger(task.getTrigger()));
            SCHEDULED_FUTURE.put(task.getTaskId(), schedule);
            TASKS.put(task.getTaskId(), task);
            log.info("任务id=" + task.getTaskId() + "已经启动成功.");
        } catch (Exception e) {
            log.info(e);
            throw e;
        }

    }

    /**
     * 停止一个计划任务.
     *
     * @param taskId 任务编号.
     */
    public void stop(String taskId) throws Exception {
        log.info("正在停止任务 " + taskId);
        if (StringUtils.isEmpty(taskId)) {
            throw new Exception("任务id不能为空.");
        }
        try {
            ScheduledFuture<?> scheduledFuture = SCHEDULED_FUTURE.remove(taskId);
            if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
                //false 表示当前任务若正在执行，则待其执行结束，再结束此任务.
                scheduledFuture.cancel(true);
            }
        } catch (Exception e) {
            log.info(null, e);
            throw e;
        }
    }

    /**
     * 重新设置当前任务的执行频率
     * @param taskId 任务编号
     * @param cronExpression 触发器表达式
     */
    public void resetTrigger(String taskId, String cronExpression) throws Exception{
        log.info("正在修改当前任务 " + taskId + "执行频率.");

        if (StringUtils.isEmpty(taskId)) {
            throw new Exception("任务id不能为空.");
        }

        if (StringUtils.isEmpty(cronExpression)) {
            throw new Exception("任务的调度表达式不能为空.");
        }

        if (!RegexpValidate.checkCronExpression(cronExpression)) {
            throw new Exception("任务的调度表达式格式错误.");
        }

        TaskRunnable task = TASKS.get(taskId);
        if(task!=null){
            if(cronExpression.equals(task.getTrigger())){
                return;
            }


            //1. stop the task
            ScheduledFuture<?> scheduledFuture = SCHEDULED_FUTURE.remove(taskId);
            /* 參數為true表示线程中断，取消任务；为false表示线程执行完后再取消任务
             * 返回值：
             *  如果status == true，说明什么意思呢？
             *   有三种可能：
             *   1. 任务还没有被执行就取消了；
             *   2. 任务已经执行完毕；
             *   3. 任务正在执行，因为输入参数是false，所以任务继续执行；
             */
            scheduledFuture.cancel(false);

            //2. reset the task with cronExpression
            task.setTrigger(cronExpression);

            //3. restart the task
            scheduledFuture = ct.schedule(task, new CronTrigger(cronExpression));
            SCHEDULED_FUTURE.put(taskId, scheduledFuture);
        }

    }

    /**
     * 执行一次任务
     * @param task 所要执行任务.
     */
    public void executeOneTime(TaskRunnable task) throws Exception{
        if (StringUtils.isEmpty(task.getTaskId())) {
            throw new Exception("任务id不能为空.");
        }
        ct.execute(task, 0);
    }

    /**
     * 销毁线程池中的任务.
     */
    public void destrory() {
        log.info("正在终止自动任务的线程池资源.");
        ScheduledExecutorService scheduledExecutor = (ScheduledExecutorService) ct.getConcurrentExecutor();
        try {
            scheduledExecutor.shutdownNow();
        } catch (Exception e) {
            log.info("自动任务的线程池资源清理发生异常.", e);
        } finally {
            log.info("自动任务的线程池资源清理完成.");
        }
    }

    /**
     * 判断任务是否在执行
     * @param taskId 任务id
     * @return 任务是否在执行
     */
    public boolean isRunning(String taskId){
        return SCHEDULED_FUTURE.containsKey(taskId);
    }
}
